home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS14.ADF / Oings / Zoing / zoing.c < prev    next >
C/C++ Source or Header  |  1989-01-28  |  17KB  |  552 lines

  1.  
  2. char title [] = "Zoing! 1.0 (c) 1986 Alonzo Gariepy, Public Domain";
  3.  
  4. /*  Simulates elastic collision of multiple balls in rectangular area. */
  5. /*      See the doc file accompanying this source code.                */
  6. /*                                                                     */
  7. /*  31 August 1986      Finished and released version 1.0, AMG         */
  8. /*                                                                     */
  9.  
  10. #include <exec/types.h>
  11. #include <exec/memory.h>
  12. #include <intuition/intuition.h>
  13. #include <graphics/sprite.h>
  14.  
  15. #define ONE_POINT_TWO 0          /* I'd rather do this dynamically */
  16.  
  17. #define MAXBALLS      8
  18. #define BALLS         balls_used    /* defined on command line.    */
  19. #define FRACBITS      6             /* 0<x<7 fixed point integers. */
  20. #define GRAVITY       gravity       /* defined by user. 2 is good. */
  21. #define LEVITY        levity        /* defined by user. 1 is best. */
  22. #define IS_HIRES      1             /* workbench always high res.  */
  23. #define IS_INTERLACE  is_interlace  /* variable due to interlace.  */
  24. #define STEPSPERFRAME 2             /* 0<x<? simulation resolution */
  25. #define SHIFTX        (FRACBITS-IS_HIRES)
  26. #define SHIFTY        shift_y       /* variable due to interlace.  */
  27. #define MINX          0
  28. #define MINY          0
  29. #define MAXX          (SIMX (304))
  30. #define MAXY          max_y         /* variable due to interlace.  */
  31.  
  32. /* defined in arguments */
  33. long    BALLS, IS_INTERLACE, SHIFTY, MAXY, GRAVITY, LEVITY;
  34.  
  35.  
  36. #define BALL_SPRITE     happyr
  37. #define CURSOR_SPRITE   charlie
  38. #define HEAD_SPRITE     harryr
  39. #define WEIRD_SPRITE    sunnyw
  40. #define SIZEOF_SPRITE   36    /* total words including posctl and term */
  41.  
  42. #define CURSORDX        7     /* The offset from pointer to cursor sprite */
  43. #define CURSORDY        7
  44. #define D               (SIMX (16))
  45.  
  46. #define CONX(x)         ((x) << SHIFTX)
  47. #define CONY(y)         ((y) << SHIFTY)
  48. #define SCREENX(x)      ((x) >> SHIFTX)
  49. #define SCREENY(y)      ((y) >> SHIFTY)
  50. #define SIMX(x)         ((x) << FRACBITS)
  51. #define SIMY(y)         ((y) << FRACBITS)
  52.  
  53. struct NewWindow windef = {
  54.         0, 0, 84 + 8*sizeof(title) - 7, 20,
  55.         -1, -1,
  56.         CLOSEWINDOW,
  57.         WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG | WINDOWSIZING,
  58.         NULL, NULL,
  59.         title,
  60.         NULL, NULL, 84 + 8*sizeof("Zoing!") - 9, 0, 0, 0,
  61.         WBENCHSCREEN
  62. };
  63.  
  64. extern  UWORD charlie [SIZEOF_SPRITE];
  65. extern  UWORD amused  [SIZEOF_SPRITE];
  66. /* and you thought Castro was a yogurt for Unix programmers */
  67. extern  UWORD happyw  [SIZEOF_SPRITE];
  68. extern  UWORD angryr  [SIZEOF_SPRITE];
  69. extern  UWORD happyr  [SIZEOF_SPRITE];
  70. extern  UWORD sunnyw  [SIZEOF_SPRITE];
  71. extern  UWORD harryr  [SIZEOF_SPRITE];
  72.  
  73. long    framecount  = 0;
  74. long    cursor      = 0;  /* boolean flag: window and cursor ball active */
  75. long    angry [MAXBALLS];
  76. long    alt_on [MAXBALLS];
  77.  
  78. struct  SimpleSprite spr[MAXBALLS];
  79. struct  Window       *win;
  80. struct  ViewPort     *vp;
  81.  
  82. UWORD   *sprbuf;
  83.  
  84. long    x [MAXBALLS]  = {0, SIMX(300),
  85.                                 SIMX(128),
  86.                           SIMX(114), SIMX(114),
  87.                      SIMX(100), SIMX(100), SIMX(100), };
  88.  
  89. long    y [MAXBALLS]  = {0, SIMY(10),
  90.                                 SIMY(92),
  91.                           SIMY(84), SIMY(100),
  92.                      SIMY(76), SIMY(92), SIMY(108), };
  93.  
  94. long    vx [MAXBALLS] = {0, -180,  0,  0, 0,  0, 0, 0,};
  95. long    vy [MAXBALLS] = {0,  70,   0,  0, 0,  0, 0, 0,};
  96.  
  97. UWORD   *sprites [MAXBALLS] = {charlie, sunnyw, harryr, happyr,
  98.                                happyr,  happyr, happyr, happyr, };
  99.  
  100. UWORD   *sprites_alt [MAXBALLS] = {amused, sunnyw, harryr, angryr,
  101.                                    angryr,  angryr, angryr, angryr, };
  102.  
  103. long    GfxBase, IntuitionBase;
  104.  
  105. main (argc, argv)
  106.     long argc;
  107.     char *argv[];
  108. {
  109.     int i;
  110.  
  111.     openwindow ();
  112.     arguments (argc, argv);
  113.     copysprites ();
  114.     defineballs ();
  115.  
  116.     for (;;)
  117.         {
  118.         trackcursor ();
  119.         doIDCMP ();
  120.         WaitTOF (vp);
  121.         for (i = 0; i < STEPSPERFRAME; ++i)
  122.             {
  123.             collisions ();
  124.             moveballs ();
  125.             }
  126.         showballs ();
  127.         }
  128. }
  129.  
  130. arguments (argc, argv)
  131.     long    argc;
  132.     char    *argv [];
  133. {
  134.     struct Screen  screen;
  135.     char    *name = (char *)0, usage [sizeof (title)];
  136.     long    i, string = 0;
  137.  
  138.     for (i = 0; i < sizeof (usage) - 1;)
  139.         if (name && (usage [i] = *name))
  140.             ++name, ++i;
  141.         else
  142.             {
  143.             switch (string)
  144.                 {
  145.                 case 0:  name = " Usage: ";
  146.                          string = 1;
  147.                          continue;
  148.                 case 1:  name = argv [0];
  149.                          string = 2;
  150.                          continue;
  151.                 case 2:  name = " balls(1..10) gravity(0..8) ";
  152.                          string = 3;
  153.                          continue;
  154.                 case 3:  break;
  155.                 }
  156.             break;
  157.             }
  158.     usage [sizeof(usage) - 1] = (char)0;
  159.  
  160.     BALLS = MAXBALLS;
  161.     GRAVITY = 0;
  162.     LEVITY  = 0;
  163.     switch (argc)
  164.         {
  165.         case 4:
  166.             LEVITY = atoi (argv [3]);
  167.             if (LEVITY < 0 || LEVITY > 5)
  168.                 seppuku (usage);
  169. #ifdef VERS12
  170.             if (LEVITY && ONE_POINT_TWO)
  171.                 ActivateWindow (win);
  172. #endif
  173.         case 3:
  174.             GRAVITY = atoi (argv [2]);
  175.             if (GRAVITY < 0 || GRAVITY > 10)
  176.                 seppuku (usage);
  177.         case 2:
  178.             BALLS = atoi (argv [1]) + 1;
  179.             if (*argv [1] == '?' || BALLS < 2 || BALLS > MAXBALLS)
  180.                 seppuku (usage);
  181.         default:
  182.             break;
  183.         }
  184.  
  185. #ifdef VERS12
  186.     if (ONE_POINT_TWO)
  187.         {
  188.         if (!GetScreenData (&screen, sizeof(screen), WBENCHSCREEN, NULL))
  189.             seppuku ("Zoing! No workbench.");
  190.         IS_INTERLACE = (screen.Height > 300) ? 1 : 0;
  191.         SHIFTY = FRACBITS - IS_INTERLACE;
  192.         MAXY = CONY(screen.Height) - SIMY(16);
  193.         }
  194.     else
  195.         {
  196. #endif
  197.         IS_INTERLACE = 0;
  198.         SHIFTY = FRACBITS;
  199.         MAXY = CONY(200) - SIMY(16);
  200. #ifdef VERS12
  201.         }
  202. #endif
  203. }
  204.  
  205. trackcursor ()
  206. {
  207.     static   long   oldx, oldy;
  208.     register long   xx, yy;
  209.  
  210.     if (win->Flags & WINDOWACTIVE)
  211.         {
  212.         x [0] = xx = CONX (win->WScreen->MouseX) - SIMX (CURSORDX);
  213.         y [0] = yy = CONY (win->WScreen->MouseY) - SIMX (CURSORDX);
  214.  
  215.         if (cursor)
  216.             {
  217.             vx [0] = (xx - oldx) / STEPSPERFRAME;
  218.             vy [0] = (yy - oldy) / STEPSPERFRAME;
  219.             }
  220.         else
  221.             {
  222.             vx [0] = vy [0] = 0;
  223.             cursor = 1;
  224.             }
  225.         oldx = xx;
  226.         oldy = yy;
  227.         }
  228.     else
  229.         {
  230.         cursor = 0;
  231.         }
  232. }
  233.  
  234.  
  235. moveballs ()         /* move the balls and reflect from walls */
  236. {
  237.     register int     i;
  238.  
  239.     x [0] += vx [0];
  240.     y [0] += vy [0];
  241.  
  242.     for (i = 1; i < BALLS; i++)
  243.         {
  244.         x [i] += vx [i];
  245.         y [i] += vy [i];
  246.  
  247.         for (;;)    /* we might require several bounces */
  248.             {
  249.             if (x [i] <= MINX)
  250.                 x [i] = MINX + MINX - x [i], vx [i] = -vx [i];
  251.             if (x [i] >= MAXX)
  252.                 x [i] = MAXX + MAXX - x [i], vx [i] = -vx [i];
  253.             if (x [i] >= MINX)
  254.                 break;
  255.             }
  256.  
  257.         vy [i] += LEVITY;
  258.         for (;;)
  259.             {
  260.             if (y [i] <= MINY)
  261.                 y [i] = MINY + MINY - y [i], vy [i] = -vy [i];
  262.             if (y [i] >= MAXY)
  263.                 y [i] = MAXY + MAXY - y [i], vy [i] = -vy [i];
  264.             if (y [i] >= MINY)
  265.                 break;
  266.             }
  267.         vy [i] += GRAVITY;
  268.         }
  269. }
  270.  
  271. showballs ()
  272. {
  273.     int        i;
  274.  
  275.     ++framecount;
  276.  
  277.     for (i = 1; i < BALLS; ++i)
  278.         {
  279.         if (alt_on [i] != angry [i])
  280.             {
  281.             ChangeSprite (vp, spr+i, angry[i] ? sprites_alt[i] : sprites[i]);
  282.             alt_on [i] = angry [i];
  283.             }
  284.         MoveSprite (vp, spr + i, SCREENX (x [i]), SCREENY (y [i]));
  285.         }
  286.  
  287. /* I used to make the cursor gloat here, but it was too distracting! */
  288. }
  289.  
  290. openwindow ()
  291. {
  292.  
  293.     if (!(IntuitionBase = OpenLibrary ("intuition.library", 0)))
  294.         seppuku ("Zoing! Can't open Intuition.");
  295.  
  296.     if (!(GfxBase = OpenLibrary ("graphics.library", 0)))
  297.         seppuku ("Zoing! Can't open graphics.");
  298.  
  299.     if (!(win = (struct Window *) OpenWindow (&windef)))
  300.         seppuku ("Zoing! Can't open window.");
  301.     vp = (struct ViewPort *) ViewPortAddress (win);
  302. }
  303.  
  304. defineballs ()
  305. {
  306.     long    i, j, color, red, green, blue;
  307.  
  308.     for (i = 16; i <= 19; ++i)
  309.         {
  310.         color = GetRGB4 (vp->ColorMap, i);
  311.         red   = color >> 8 & 0xF;
  312.         green = color >> 4 & 0xF;
  313.         blue  = color      & 0xF;
  314.  
  315.         for (j = 4; j <= 12; j += 4)
  316.             SetRGB4 (vp, i + j, red, green, blue);
  317.         }
  318.  
  319.     for (i = 1; i < BALLS; i++)
  320.         {
  321.         if (GetSprite (spr + i, -1) < 0)
  322.             seppuku ("Zoing! Sprite allocation failed. ");
  323.  
  324.         spr [i].height = 16;
  325.         spr [i].x = SCREENX (x [i]);
  326.         spr [i].y = SCREENY (y [i]);
  327.  
  328.         ChangeSprite (vp, spr + i, sprites [i]);
  329.         }
  330.  
  331.     SetPointer (win, sprites [0], 16, 16, -CURSORDX, -CURSORDY);
  332.     SetWindowTitles (win, title, title);
  333. }
  334.  
  335. free_resources ()
  336. {
  337.         register int i;
  338.  
  339.         for (i = 1; i < BALLS; i++)
  340.                 if (spr [i].num)
  341.                         FreeSprite ((long) spr [i].num);
  342.  
  343.         if (sprbuf)
  344.                 FreeMem (sprbuf, 2*2*SIZEOF_SPRITE * BALLS);
  345.         if (win)
  346.                 CloseWindow (win);
  347.         if (GfxBase)
  348.                 CloseLibrary (GfxBase);
  349.         if (IntuitionBase)
  350.                 CloseLibrary (IntuitionBase);
  351. }
  352.  
  353. doIDCMP ()
  354. {
  355.     long    msg;
  356.  
  357.     if (msg = GetMsg (win -> UserPort))
  358.         {
  359.         ReplyMsg (msg);
  360.         free_resources ();
  361.         /* printf ("framecount = %ld\n", framecount); */
  362.     /* Sorry, not under Workbench. jjf 06-sep-86 */
  363.         exit (0);
  364.         }
  365. }
  366.  
  367. seppuku (str)
  368.     char *str;
  369. {
  370.     if (win)
  371.         {
  372.         SetWindowTitles (win, str, -1);
  373. #ifdef VERS12
  374.         if (ONE_POINT_TWO)
  375.             ActivateWindow (win);               /* don't die quietly */
  376. #endif
  377.         WaitPort (win -> UserPort);
  378.         }
  379.     free_resources ();
  380.     exit (100);
  381. }
  382.  
  383. copysprites ()
  384. {
  385.     UWORD   *cw;       /* current position in buffer of sprite images */
  386.     UWORD   *sprite;   /* current position in sprite                  */
  387.     int     i, j;
  388.  
  389.     if (!(sprbuf = (UWORD *)
  390.                 AllocMem (2 * 2*SIZEOF_SPRITE * BALLS, MEMF_CHIP)))
  391.         seppuku ("Zoing! Can't allocate sprite buffer. ");
  392.  
  393.     cw = sprbuf;    /* current position at top of buffer */
  394.  
  395.  
  396.     for (i = 0; i < BALLS; ++i)
  397.         {
  398.         sprite = sprites [i];
  399.         if (!sprite)
  400.             seppuku ("Zoing! Missing sprite definition. ");
  401.         sprites [i] = cw;
  402.         for (j = 0; j < SIZEOF_SPRITE; ++j)
  403.             *cw++ = *sprite++;
  404.         }
  405.  
  406.     for (i = 0; i < BALLS; ++i)
  407.         {
  408.         sprite = sprites_alt [i];
  409.         if (!sprite)
  410.             seppuku ("Zoing! Missing sprite definition. ");
  411.         sprites_alt [i] = cw;
  412.         for (j = 0; j < SIZEOF_SPRITE; ++j)
  413.             *cw++ = *sprite++;
  414.         }
  415. }
  416.  
  417. collisions ()
  418. {
  419.     /* These are statics so we don't have to worry about stack size. */
  420.     long   i, j;
  421.     long   dx, dy, dh, halfdh, dvx, dvy, evx, evy;
  422.  
  423.     for (i = cursor ? 0 : 1;  i < BALLS; ++i)
  424.         for (j = i+1; j < BALLS; ++j)
  425.             {
  426.             dx = x [i] - x [j];
  427.             dy = y [i] - y [j];
  428.  
  429.             if (dx > D || dx < -D || dy > D || dy < -D)
  430.                 continue;
  431.  
  432.             dh = dx*dx + dy*dy;
  433.                            /* big chunk of fudge */
  434.             if (dh > D*D + (2 << 2*FRACBITS))
  435.                 continue;
  436.  
  437.             dvx = vx [i] - vx [j];
  438.             dvy = vy [i] - vy [j];
  439.  
  440.             if (i == 0)
  441.                 {
  442.                 dvx = dvx*2 - dvx/2;  /* first term:   infinite mass */
  443.                 dvy = dvy*2 - dvy/2;  /* second term:  bit inelastic */
  444.                 }
  445.  
  446.             evx = dx * dvx + dy * dvy;      /* sign of relative speed */
  447.  
  448.             if (evx >= 0)  /* same velocity or position, or departing */
  449.                 continue;
  450.  
  451. /* Since energy is proportional to the square of the velocity, simple   */
  452. /* rounding does not work (errors won't necessarily balance over time). */
  453. /* We'll try to make sure that the middle round value always is rounded */
  454. /* down by subtracting one from halfdh.                                 */
  455.  
  456.             halfdh = dh/2 - 1;   /* if anything we lose energy */
  457.  
  458.             evx = evx * dx;
  459.             if (evx > 0)
  460.                 evx = (evx + halfdh) / dh;
  461.             else
  462.                 evx = (evx - halfdh) / dh;
  463.             evy = (dx * dvy - dy * dvx) * dx;
  464.             if (evy > 0)
  465.                 evy = dvy - (evy + halfdh) / dh;
  466.             else
  467.                 evy = dvy - (evy - halfdh) / dh;
  468.  
  469.             if (i)    /* cursor doesn't change speed */
  470.                 vx [i] -= evx, vy [i] -= evy;
  471.             vx [j] += evx;
  472.             vy [j] += evy;
  473.  
  474.             /* some cute display stuff */
  475.             switch (i)      /* personalities */
  476.                 {
  477.                 case 0:
  478.                     if (j > 2)
  479.                         angry [j] = 1;          /* yuck! */
  480.                     break;
  481.                 case 1: case 2:             /* the fun guys cheer */
  482.                     angry [j] = 0;          /* everybody up       */
  483.                     break;
  484.                 default:
  485.                     angry [i] |= angry [j]; /* infectious grief */
  486.                     angry [j] |= angry [i];
  487.                     break;
  488.                 }
  489.             }
  490. }
  491.  
  492. UWORD charlie [] =   { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8,
  493.                        0x0020, 0x3ffc, 0x00f0, 0x7ffe, 0x0ff8, 0x7ffe,
  494.                        0x33cc, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
  495.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xfe7f, 0xffff,
  496.                        0x7ffe, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  497.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  498.                      };
  499.  
  500. UWORD amused [] =    { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8,
  501.                        0x0020, 0x3ffc, 0x00f0, 0x7ffe, 0x0ff8, 0x7ffe,
  502.                        0x33cc, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
  503.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xfe7f, 0xffff,
  504.                        0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  505.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  506.                      };
  507.  
  508. UWORD happyw [] =    { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0020, 0x1ff8,
  509.                        0x0070, 0x3ffc, 0x0ff8, 0x7ffe, 0x3ffc, 0x7ffe,
  510.                        0xf3cf, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
  511.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xeff7, 0xffff,
  512.                        0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  513.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  514.                      };
  515.  
  516. UWORD angryr [] =    { 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8, 0x0000,
  517.                        0x3ffc, 0x0000, 0x73ce, 0x0c30, 0x7dbe, 0x0240,
  518.                        0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xfeff, 0x0100,
  519.                        0xfdbf, 0x0240, 0xfe7f, 0x0180, 0xffff, 0x0000,
  520.                        0x7ffe, 0x0000, 0x781e, 0x07e0, 0x3ffc, 0x0000,
  521.                        0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
  522.                      };
  523.  
  524. UWORD happyr [] =    { 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8, 0x0000,
  525.                        0x3ffc, 0x0000, 0x7ffe, 0x0000, 0x7ffe, 0x0000,
  526.                        0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xffff, 0x0000,
  527.                        0xffff, 0x0000, 0xffff, 0x0000, 0xeff7, 0x1008,
  528.                        0x77ee, 0x0810, 0x781e, 0x07e0, 0x3ffc, 0x0000,
  529.                        0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
  530.                      };
  531.  
  532. UWORD sunnyw [] =    { 0x0000, 0x0000, 0x07e0, 0x07e0, 0x1ff8, 0x1ff8,
  533.                        0x3ffc, 0x3ffc, 0x7ffe, 0x2184, 0x73ce, 0x4c32,
  534.                        0xf3cf, 0xedb7, 0xffff, 0xe187, 0xfeff, 0xffff,
  535.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xeff7, 0xffff,
  536.                        0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  537.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  538.                      };
  539.  
  540. UWORD harryr [] =    { 0x0000, 0x0000, 0x07e0, 0x07e0, 0x1ff8, 0x1fd8,
  541.                        0x3ffc, 0x3f8c, 0x7ffe, 0x7006, 0x7ffe, 0x4002,
  542.                        0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xfeff, 0x0100,
  543.                        0xfdbf, 0x0240, 0xfe7f, 0x0180, 0xeff7, 0x1008,
  544.                        0x77ee, 0x0810, 0x781e, 0x07e0, 0x3ffc, 0x0000,
  545.                        0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
  546.                      };
  547.  
  548. /*  This program was created with Vladimir Schwartz's editor, PTE, the  */
  549. /*  best likely ever to be available for the Amiga.  The sprite images  */
  550. /*  were designed using Ray R. Larson's SpriteMaker.  Funny how Charlie */
  551. /*  Chaplin and his look alike symbolize similar organizations...       */
  552.